﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace tamzarian
{
    /// <summary>
    /// Dual numbers a0 + ε * ae
    /// where ε is the Dual unit satisfying ε^2 = 0
    /// </summary>
    public struct Dual
    {
        public readonly double a0;
        public readonly double ae;

        public Dual(double a0, double ae)
        {
            this.a0 = a0;
            this.ae = ae;
        }

        #region Override Object Methods

        public override string ToString()
        {
            return string.Format("DualDouble({0}, {1})", a0, ae);
        }

        public override int GetHashCode()
        {
            return a0.GetHashCode() ^ a0.GetHashCode();
        }

        public override bool Equals(object other)
        {
            return other is Dual && Equals((Dual)other);
        }

        public override bool Equals(Dual other)
        {
            return a0 == other.a0 && ae == other.ae;
        }

        public static bool operator ==(Dual lhs, Dual rhs)
        {
            return lhs.Equals(rhs);
        }

        public static bool operator !=(Dual lhs, Dual rhs)
        {
            return !lhs.Equals(rhs);
        }

        #endregion

        #region Arithmetic

        public static Dual operator +(Dual lhs, Dual rhs)
        {
            return new Dual(lhs.a0 + rhs.a0, lhs.ae + rhs.ae);
        }

        public static Dual operator *(Dual lhs, Dual rhs)
        {
            return new Dual(lhs.a0 * rhs.a0, lhs.a0 * rhs.ae + lhs.ae * rhs.a0);
        }

        public Dual Conjugate()
        {
            return new Dual(a0, - ae);
        }

        public Dual Reciprocal()
        {
            return new Dual(1 / a0, -ae / (a0 * a0));
        }

        public Dual Sqrt()
        {
            double sqrt0 = Math.Sqrt(a0);
            return new Dual(sqrt0, ae / (2 * sqrt0));
        }

        #endregion
    }
}
